import { reactive, ref } from 'vue'
import { useI18n } from 'vue-i18n'

import { sleep } from '@/utils/sleep'
import { arrowPosition, slotPosition, StatusStyle } from './constants'

import type { ModuleSlot, DragMeta, DebuggerInfo } from './types'

import source from '@/assets/images/mimo/source.svg'
import modulation from '@/assets/images/mimo/modulation.svg'
import encoder from '@/assets/images/mimo/encoder.svg'
import channel from '@/assets/images/mimo/channel.svg'
import noise from '@/assets/images/mimo/noise.svg'
import decoder from '@/assets/images/mimo/decoder.svg'
import demodulation from '@/assets/images/mimo/demodulation.svg'
import constellation from '@/assets/images/mimo/constellation.svg'

export function useModuleData() {
  const { t } = useI18n<[typeof import('./locales/zh-CN.json')]>({ useScope: 'local' })

  /** @desc 箭头状态 */
  const arrowData = ref<string[]>([])
  /** @desc 模块拼图数据, 也是拖拽指令所需数据 */
  const moduleData = reactive<DragMeta>({
    moduleSlots: [],
    moduleSourceList: [
      { id: 0, name: t('moduleData.part.source'), svg: source },
      { id: 1, name: t('moduleData.part.modulation'), svg: modulation },
      { id: 2, name: t('moduleData.part.encoder'), svg: encoder },
      { id: 3, name: t('moduleData.part.channel'), svg: channel },
      { id: 4, name: t('moduleData.part.noise'), svg: noise },
      { id: 5, name: t('moduleData.part.decoder'), svg: decoder },
      { id: 6, name: t('moduleData.part.demodulation'), svg: demodulation },
      { id: 7, name: t('moduleData.part.constellation'), svg: constellation }
    ].sort(() => (Math.random() > 0.5 ? 1 : -1))
  })

  resetModuleStyle()
  /** @desc 重置样式 */
  function resetModuleStyle() {
    arrowData.value = arrowPosition.map((p) => `${p} ${StatusStyle.ArrowPending}`)

    if (moduleData.moduleSlots.length === 0) {
      moduleData.moduleSlots = slotPosition.map<ModuleSlot>((position, id) => ({
        id,
        style: `${position} ${StatusStyle.SlotPending}`
      }))
    }
    moduleData.moduleSlots.forEach(
      (slot) => (slot.style = `${slot.style.split(' ')[0]} ${StatusStyle.SlotPending}`)
    )
  }

  let lock = false
  const debuggerInfo = reactive<DebuggerInfo>([])
  async function checkModule() {
    if (lock) return
    lock = true
    resetModuleStyle()
    await sleep()
    debuggerInfo.push(['INFO', t('moduleData.log.starting')])
    if (moduleData.moduleSourceList.length !== 0) {
      await sleep()
      debuggerInfo.push(['WARN', t('moduleData.log.notReady')])
      return (lock = false)
    }

    for (const slot of moduleData.moduleSlots) {
      await sleep()
      if (slot.id !== slot.module!.id) {
        if (slot.id != 0) arrowData.value[slot.id - 1] += ' ' + StatusStyle.ArrowError
        debuggerInfo.push(['ERROR', t('moduleData.log.error', { name: slot.module?.name })])
        slot.style = `${slot.style} ${StatusStyle.SlotError}`
        return (lock = false)
      } else {
        if (slot.id != 0) arrowData.value[slot.id - 1] += ' ' + StatusStyle.ArrowSuccess
        debuggerInfo.push(['INFO', t('moduleData.log.passing', { name: slot.module?.name })])
        slot.style = `${slot.style} ${StatusStyle.SlotSuccess}`
      }
    }

    debuggerInfo.push(['SUCCESS', t('moduleData.log.allPassing')])
    lock = false
  }

  return {
    arrowData,
    moduleData,
    checkModule,
    debuggerInfo
  }
}
